/*
 * LianHaidong <lianhaidong@gmail.com>
 */

#include <sys/types.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "utils/hash.h"
#include "utils/debug.h"

struct hash_list *hash_create(hash_func_t func, key_compare_t comp, uint32_t index_count)
{
	struct hash_list *hl = NULL;
	int size = sizeof(*hl) + sizeof(struct node *) * index_count;
	hl = malloc(size);

	if (!hl) {
		debug("Out of memory");
		return NULL;
	}
	
	memset(hl, 0, size);
	hl->func = func;
	hl->comp = comp;
	hl->index_count = index_count;
	return hl;
}

int hash_delete(struct hash_list *hl)
{
	int i;
	
	for (i = 0; i < hl->index_count; i++) {
		struct hash_node *n = hl->node[i];
		while (n) {
			struct hash_node *p = n;
			n = n->next;
			free(p);
		}
	}

	return 0;
}


int hash_list_insert(struct hash_list *hl, void *data, void *key)
{
	struct hash_node *node = NULL;
	int index;

	index = hl->func(key);

	assert(index < hl->index_count);

	node = malloc(sizeof(*node));

	if (!node) {
		debug("Outof Memory");
		return -ENOMEM;
	}

	debug("data = %p", data);
	node->data = data;
	node->key = key;
	node->next = hl->node[index];		
	hl->node[index] = node;
	hl->node_count ++;

	return 0;	
}



void *hash_list_delete(struct hash_list *hl, void *key)
{
	void *data = NULL;
	uint32_t index = hl->func(key);
	struct hash_node **ppn;
	
	assert(index < hl->index_count);

	ppn = &hl->node[index];

	while (*ppn) {
		if (hl->comp((*ppn)->key, key) == 0) {
			struct hash_node *n = *ppn;
			*ppn = (*ppn)->next;	
			data = n->data;
			free(n);
			hl->node_count --;
			break;
		}
		ppn = &((*ppn)->next);
	}

	return data;
}

void *hash_list_peer(struct hash_list *hl, void *key)
{
	void *data = NULL;
	uint32_t index; 
	struct hash_node *n;

	index = hl->func(key);
	assert(index < hl->index_count);

	n = hl->node[index];

	while (n) {
		if (hl->comp(n->key, key) == 0) {
			data = n->data;
			break;
		}
		n = n->next;
	}	
	
	return data;
}

